/**
 *
 */
package com.googlecode.pkchat.pkserver;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Hashtable;

/**
 * @author Simon Pratt
 *
 */
public class Server {

	ServerSocket ss;

	private Hashtable outputStreams;

	/**
	 *
	 */
	public Server(int port) throws IOException {
		outputStreams = new Hashtable();
		listen(port);
	}

	private void listen(int port) throws IOException{
		DataInputStream din;
		ss = new ServerSocket(port);
		System.out.println("PKChat Server listening on port "+ss.getLocalPort());
		while(true){
			UserSocket s = new UserSocket(ss.accept());
			System.out.println("Connection from "+s.getSocket().getInetAddress());
			this.sendToAll("Connection from "+s.getSocket().getInetAddress());
			DataOutputStream dout = new DataOutputStream(s.getOutputStream());
			outputStreams.put(s,dout);
			new ServerThread(this,s);
			broadcastUsers();
		}
	}

	Enumeration getOutputStreams(){
		return outputStreams.elements();
	}

	void sendToAll(String message){
		synchronized(outputStreams){
			for(Enumeration e = getOutputStreams();e.hasMoreElements();){
				DataOutputStream dout = (DataOutputStream) e.nextElement();

				try{
					dout.writeUTF(message);
				}
				catch(IOException ioe){
					System.out.println(ioe);
				}
			}
		}
	}

	Enumeration getUsers(){
		return outputStreams.keys();
	}

	void broadcastUsers(){
		String broadcast = "\u2580 ";
		synchronized(outputStreams){
			for(Enumeration e = getUsers();e.hasMoreElements();){
				UserSocket luser = (UserSocket) e.nextElement();
				broadcast += luser.getName();
			}
		}
		//broadcast += " \u2581";
		sendToAll(broadcast);
	}

	void removeConnection(UserSocket socket){
		synchronized(outputStreams){
			outputStreams.remove(socket);
			try{
				sendToAll(socket.getName()+" has left the server.");
				System.out.println("Connection from "+socket.getSocket().getLocalAddress()+" closed.");
				socket.getSocket().close();
				broadcastUsers();
			}catch(Exception e){
				System.out.println("Error closing socket "+socket);
				e.printStackTrace();
			}
		}
	}

	UserSocket getSocket(String user){
		UserSocket found = null;
		synchronized(outputStreams){
			for(Enumeration e = getUsers();e.hasMoreElements();){
				UserSocket luser = (UserSocket) e.nextElement();
				if(luser.getName().equals(user))
					return luser;
			}
		}
		return found;
	}

	void serverMessage(String toUser,String message){
		UserSocket toWhisper = getSocket(toUser);
		if(toWhisper!=null){
			DataOutputStream toOut = (DataOutputStream) outputStreams.get(toWhisper);
			try{
				toOut.writeUTF(message);
			}catch(IOException e){}
		}else System.out.println("Server message to "+toUser+" failed.");
	}

	void whisper(String toUser,String fromUser,String message){
		DataOutputStream toOut, fromOut;
		synchronized(outputStreams){
			UserSocket toWhisper = getSocket(toUser);
			if(toWhisper!=null){
				toOut = (DataOutputStream) outputStreams.get(toWhisper);
				try{
					toOut.writeUTF("\u2582 "+fromUser+" "+message);
				}catch(IOException e){}
			}
			else {
				try{
					UserSocket fromWhisper = getSocket(fromUser);
					fromOut = (DataOutputStream) outputStreams.get(fromWhisper);
					fromOut.writeUTF(toUser+" not found!");
				}catch(IOException e){}

			}
		}
	}
}
